package com.mycom.wxTest;

import com.alibaba.fastjson.JSONObject;
import com.mycom.common.base.AbstractService;
import com.mycom.common.utils.MD5Util;
import com.mycom.common.wxpay.PayCnst;
import com.mycom.common.wxpay.WdPayBase;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

/**
 * 不需输入验证码场景下: 玩家绑定, 发送红包
 * @author xp
 * Created on 2018/3/16
 */
@Service
public class RedPkgService extends AbstractService {
    Logger log = LogManager.getLogger(getClass());

    /**
     * @param code
     * @return
     */
    public JSONObject bindUnionid(String code, String gameId) {
        JSONObject json = new JSONObject();
        json.put("result", false);

        if ((code == null) || (gameId == null)) {
            log.warn("参数为空! code: " + code + ", gameId: " + gameId);
            return json;
        }

        String[] strArray = WdPayBase.getOpenidAndUnionid(code, gameId);
        if (strArray == null) {
            return json;
        }

        String openid  = strArray[0];
        String unionId = strArray[1];

        JSONObject j = vdUserBind(unionId, gameId);
        if (j.getBoolean("result")) {
            return j;
        }

        Unionid unionid = new Unionid();

        unionid.setUnionId(unionId);
        unionid.setOpenId(openid);
        unionid.setGameId(gameId);

        String collectionName = "unionid";
        mongoDao.insert(unionid, collectionName);

        return vdUserBind(unionId, gameId);
    }

    /**
     * 验证玩家的unionid是否绑定openid
     * @param unionId
     * @return
     */
    public JSONObject vdUserBind(String unionId, String gameId) {
        JSONObject json = new JSONObject();
        json.put("result", false);

        if (unionId == null) {
            log.warn("参数为空!");
            return json;
        }

        if (gameId == null) {
            gameId = "HY_NJ_GD";
        }

        String openid = getOpenid(unionId, gameId);
        log.info("openid" + openid + ", unionId: " + unionId);
        int openidLen = 20;
        boolean legalArgs = (openid != null) && (openid.length() >= openidLen);
        if (legalArgs) {
            json.put("result", true);
        }

        return json;
    }

    private String getOpenid(String unionId, String gameId) {
        Criteria criteria = new Criteria();
        criteria.and("unionId").is(unionId);
        criteria.and("gameId").is(gameId);

        Query query = new Query();
        query.addCriteria(criteria);
        query.fields().include("openId");

        String collectionName = "unionid";
        Unionid unionid = mongoDao.findOne(query, collectionName, Unionid.class);

        boolean illegalArgs = (unionid == null) || (unionid.getOpenId() == null);
        if (illegalArgs) {
            return null;
        }

        return unionid.getOpenId();
    }

    /**
     * 兑换==发送红包接口
     *
     * @return  errCode->1:参数为空, 2:验签失败, 3:获取红包金额失败, 4:获取openid失败
     * @throws UnsupportedEncodingException
     */
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, noRollbackFor = Exception.class)
    public JSONObject sendRedPacket(String f_record_id, String unionId, String num, String ip, String sign, String gameId) {
        JSONObject json = new JSONObject();
        json.put("result", false);
        json.put("msg", "发送失败");

        if ((f_record_id == null) || (unionId == null) || (ip == null) || (num == null) || (sign == null)) {
            json.put("errCode", 1);
            log.warn("参数为空!");
            return json;
        }

        // MD5解密
        boolean res = checkSign(f_record_id, unionId, num, ip, gameId, sign);
        if (res == false){
            json.put("errCode", 2);
            json.put("msg", "验签失败");
            log.warn("验签失败! f_record_id: " + f_record_id);
            return json;
        }

        if (gameId == null) {
            gameId = "HY_NJ_GD";
        }

        Double num2 = Double.parseDouble(num);
        if ((num2 == null) || (num2 == 0)) {
            json.put("errCode", 3);
            json.put("msg", "获取红包金额失败!");
            log.warn("获取红包金额失败! f_record_id: " + f_record_id);
            return json;
        }

        String openid = getOpenid(unionId, gameId);
        if ((openid == null) || (openid.length() < PayCnst.openid_len)) {
            json.put("errCode", 4);
            json.put("msg", "获取openid失败!");
            log.warn("获取openid失败! unionId: " + unionId);
            return json;
        }

        // 验证不存在此记录 true: 重复  false: 不重复
        if (checkRecordRepeat(f_record_id)) {
            json.put("errCode", 5);
            json.put("msg", "此红包记录已存在, f_record_id: " + f_record_id);
            log.warn("此红包记录已存在, f_record_id: " + f_record_id);
            return json;
        }

        // 插入红包详情 -- 状态是 3: 转账中
        RedPkgDetail redPkgDetail = genRedPkgDetail(f_record_id, num2, openid, ip, gameId);
        if (!saveRedPkgDetail(redPkgDetail)) {
            json.put("errCode", 6);
            json.put("msg", "保存红包记录失败, f_record_id: " + f_record_id);
            log.warn("保存红包记录失败, f_record_id: " + f_record_id);
            return json;
        }

        // 发红包
        rmtSendRedPkg(redPkgDetail);

        // 更新状态
        if (!updateRedPkgDetail(redPkgDetail)) {
            json.put("errCode", 7);
            json.put("msg", "更新红包记录失败, f_record_id: " + f_record_id);
            log.warn("更新红包记录失败, f_record_id: " + f_record_id);
            return json;
        }

        if (redPkgDetail.transState == PayCnst.transState_success) {
            json.put("result", true);
            json.put("msg", "发送成功!");
        }

        return json;
    }

    private boolean checkSign(String f_record_id, String unionId, String num, String ip, String gameId, String sign){
        Map<String,String> params = new HashMap<>();
        params.put("f_record_id", f_record_id);
        params.put("unionId", unionId);
        params.put("num", num);
        params.put("ip", ip);
        params.put("gameId", gameId);

        return MD5Util.redPkgSignCheck(params, sign);
    }

    /**
     * 保存发放红包详情
     *
     * @return
     */
    protected boolean saveRedPkgDetail(RedPkgDetail redPkgDetail) {
        String f_record_id  = redPkgDetail.f_record_id;
        String out_trade_no = redPkgDetail.out_trade_no;
        String payment_no   = redPkgDetail.payment_no;
        String money        = redPkgDetail.money.toString();
        String transState   = redPkgDetail.transState.toString();
        String openid       = redPkgDetail.openid;
        String ip           = redPkgDetail.ip;
        String err_code_des = redPkgDetail.err_code_des;
        String payment_time = redPkgDetail.payment_time;

        String sql = "insert into lottery.redPkgDetail(f_record_id, out_trade_no, payment_no, money, transState, openid, ip, "
                + "err_code_des, payment_time) values (?,?,?,?,?,?,?,?,?)";

        int count = jdbcDao.update(sql, new Object[]{f_record_id, out_trade_no, payment_no, money, transState, openid,
                ip, err_code_des, payment_time});

        log.info("保存发放红包详情" + (count > 0 ? "成功" : "失败") + ", f_record_id: " + f_record_id);
        if (count > 0) {
            return true;
        }

        return false;
    }

    private boolean updateRedPkgDetail(RedPkgDetail redPkgDetail) {
        String sql = "update lottery.redPkgDetail set payment_no=?, payment_time=?, transState=?, err_code_des=? where f_record_id=?";
        int count = jdbcDao.update(sql, new Object[]{redPkgDetail.payment_no, redPkgDetail.payment_time, redPkgDetail.transState,
                redPkgDetail.err_code_des, redPkgDetail.f_record_id});

        log.info("更新发放红包详情" + (count > 0 ? "成功" : "失败") + ", f_record_id: " + redPkgDetail.f_record_id);
        if (count > 0) {
            return true;
        }

        return false;
    }

}
